#include "SocketIO.h"

SocketIO::SocketIO(int fd) 
:_fd(fd)
{}

int SocketIO::readn(char * buf, int len) {
    int left = len; //剩余要读的字节数
    char *pstr = buf;   
    int ret = 0;
    while(left > 0){
        ret = read(_fd,pstr,left);
        if(-1 == ret && errno == EINTR){
            continue;
        }else if(-1 == ret){
            perror("read error -1");
            exit(1);
        }else if(0 == ret){
            break;
        }else{
            pstr += ret;
            left -= ret;
        }
    }
    return len - left;
}

int SocketIO::writen(char* buf, int len) {
    int left = len; //剩余要写的字符数
    char *pstr = buf;
    int ret = 0; //每次写入的字节数

    while(left > 0){
        ret = ::send(_fd,pstr,left,MSG_NOSIGNAL);
        if(-1 == ret && errno == EINTR){
            continue;
        }else if(-1 == ret){
            perror("writen error -1");
            return -1;
        }else if(0 == ret){
            break;
        }else{
            pstr += ret;
            left -= ret;
        }
    }

    return len - left;
}

int SocketIO::readLine(char* buf, int len) {
    int left = len - 1;
    char *pstr = buf;
    int ret =0,total = 0;
    
    while(left > 0){
        //MSG_PEEK不会将缓冲区中的数据进行清空，只会进行拷贝操作
        ret = recv(_fd,pstr,left,MSG_PEEK);
        if(-1 == ret && errno == EINTR){
            continue;
        }else if(-1 == ret){
            perror("readLine error -1");
            exit(1);
        }else if(0 == ret){
            break;
        }else{
            for(int idx = 0;idx < ret; ++idx){
                if(pstr[idx]=='\n'){
                    int sz = idx + 1; 
                    readn(pstr,sz);
                    pstr += sz;
                    *pstr = '\0';   //C风格字符串以'\0'结尾
                    return total+sz;    //返回读到的总字节数
                }
            }
            readn(pstr,ret);    //从内核态拷贝到用户态
            total += ret;
            pstr += ret;
            left -= ret;

        }
    }
   *pstr = '\0';
   return total; //返回读到的总字节数
}

int SocketIO::readTrain(train_t& train){
    int length = 0;
    readn((char*)&length,sizeof(train.length));
    train.length = length;
    int type = 0;
    readn((char*)&type,sizeof(train.type));
    train.type = type;
    train.jsonObj.reserve(train.length);
    char* content = (char*)malloc(train.length+1);
    bzero(content,train.length+1);
    readn(content,train.length);
    train.jsonObj = string(content);
    free(content);
    return 0;
}

int SocketIO::writeTrain(const train_t& train){
    int length = train.length;
    writen((char*)&length,sizeof(train.length));
    int type = train.type; 
    writen((char*)&type,sizeof(train.type));
    string content = train.jsonObj;
    writen((char*)content.c_str(),train.jsonObj.size());
    return 0;
}


SocketIO::~SocketIO() {
    ::close(_fd);
}
